package cn.exrick.service.impl;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;

import cn.exrick.mapper.BaseMapper;
import cn.exrick.pojo.BasePojo;
import cn.exrick.service.BaseService;
import cn.exrick.utils.mybatis.Criteria;
import cn.exrick.utils.mybatis.Page;
import cn.exrick.utils.mybatis.PageParam;

public abstract class BaseServiceImpl<T extends BasePojo, MAPPER extends BaseMapper<T>> implements BaseService<T> {
    public abstract MAPPER getMapper();

    public abstract Logger getLogger();

    public static Criteria createCriteria() {
        Criteria criteria = new Criteria();
        return criteria;
    }

    public Criteria createCriteria(Map<String, Object> params) {
        Criteria criteria = createCriteria();
        for (String key : params.keySet()) {
            if (params.get(key) != null) {
                criteria.andFieldEqualTo(key, params.get(key).toString());
            }
        }
        return criteria;
    }

    @Override
    public T findById(long id) {
        return getMapper().findById(id);
    }

    @Override
    public List<T> findList(Map<String, Object> params) {
        return getMapper().findList(params);
    }

    @Override
    public int countList(Map<String, Object> params) {
        return getMapper().countList(params);
    }

    @Override
    public List<T> findAll() {
        return getMapper().findAll();
    }

    @Override
    public long save(T t) {
        if (t.getCreateTime() == null) {
            t.setCreateTime(new Date());
        }
        if (t.getUpdateTime() == null) {
            t.setUpdateTime(new Date());
        }
        return getMapper().save(t);
    }

    @Override
    public boolean update(T t) {
        t.setUpdateTime(new Date());
        long res = getMapper().update(t);
        return true;
    }

    @Override
    public void delete(T t) {
        getMapper().delete(t.getId());
    }

    @Override
    public void delete(long id) {
        getMapper().delete(id);
    }


    public Page<T> findPage(Map<String, Object> filters, PageParam pageParam) {
        if (filters == null) {
            filters = new HashMap<>();
        }
        Page<T> page = new Page<>(pageParam);
        filters.put("pageFirst", pageParam.getFirst());
        filters.put("pageSize", pageParam.getPageSize());
        if (StringUtils.isNotEmpty(pageParam.getSortFieldName())) {
            filters.put("sortFieldName", pageParam.getSortFieldName());
        }
        if (StringUtils.isNotEmpty(pageParam.getSortType())) {
            filters.put("sortType", pageParam.getSortType());
        }
        List<T> results = findList(filters);
        int count = countList(filters);
        page.setResult(results);
        page.setTotalCount(count);
        return page;
    }

    public List<T> findListByCriteria(Criteria criteria, PageParam pageParam) {
        try {
            Map<String, Object> filters = new HashMap<>();
            if (criteria == null) {
                criteria = createCriteria();
            }
            filters.put("criteria", criteria);
            if (pageParam != null) {
                filters.put("pageFirst", pageParam.getFirst());
                filters.put("pageSize", pageParam.getPageSize());
                if (StringUtils.isNotEmpty(pageParam.getSortFieldName())) {
                    filters.put("sortFieldName", pageParam.getSortFieldName());
                }
                if (StringUtils.isNotEmpty(pageParam.getSortType())) {
                    filters.put("sortType", pageParam.getSortType());
                }
            }
            return getMapper().findListByCriteria(filters);
        } catch (Exception e) {
            e.printStackTrace();
            throw e;
        }
    }

    public List<T> findListByCriteria(Criteria criteria) {
        Map<String, Object> filters = new HashMap<>();
        if (criteria == null) {
            criteria = createCriteria();
        }
        filters.put("criteria", criteria);
        return getMapper().findListByCriteria(filters);
    }

    public List<T> findListByCriteria(Map<String, Object> params) {
        return findListByCriteria(createCriteria(params));
    }

    public int countListByCriteria(Criteria criteria) {
        Map<String, Object> filters = new HashMap<>();
        if (criteria == null) {
            criteria = createCriteria();
        }
        filters.put("criteria", criteria);
        return getMapper().countListByCriteria(filters);
    }

    public Page<T> findPageByCriteria(Criteria criteria, PageParam pageParam) throws Exception {
        if (pageParam == null) {
            throw new Exception("pageParam对象不能为空");
        }
        Page<T> page = new Page<>(pageParam);
        List<T> result = findListByCriteria(criteria, pageParam);
        page.setResult(result);
        if (result != null && result.size() != 0) {
            int count = countListByCriteria(criteria);
            page.setTotalCount(count);
        } else {
            page.setTotalCount(0);
        }
        return page;
    }

    public Page<T> findPageByCriteria(Map<String, Object> params, PageParam pageParam) throws Exception {
        return findPageByCriteria(createCriteria(params), pageParam);
    }

    public Page<T> findPage(T t, PageParam pageParam) {
        Map<String, Object> filters = new HashMap<>();
        Map parameterObject = null;
        try {
            parameterObject = BeanUtils.describe(t);
        } catch (Exception e) {
            e.printStackTrace();
        }
        filters.putAll(parameterObject);
        Page<T> page = findPage(filters, pageParam);
        return page;
    }

    public List<T> findByUnique(String key, String value) {
        Criteria criteria = createCriteria();
        criteria.andFieldEqualTo(key, value);
        List<T> list = findListByCriteria(criteria);
        return list;
    }

    public T findByUniqueForOne(String key, String value) {
        List<T> list = findByUnique(key, value);
        if (list == null || list.size() <= 0) {
            return null;
        } else {
            return list.get(0);
        }
    }
}
